//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

// NOTE: This file should be synced between swift and swift-syntax repository.
// NOTE: Types in this file should be self-contained and should not depend on any non-stdlib types.

internal enum HostToPluginMessage: Codable {
  /// Get capability of this plugin.
  case getCapability

  /// Expand a '@freestanding' macro.
  case expandFreestandingMacro(
    macro: PluginMessage.MacroReference,
    discriminator: String,
    syntax: PluginMessage.Syntax
  )

  /// Expand an '@attached' macro.
  case expandAttachedMacro(
    macro: PluginMessage.MacroReference,
    macroRole: PluginMessage.MacroRole,
    discriminator: String,
    attributeSyntax: PluginMessage.Syntax,
    declSyntax: PluginMessage.Syntax,
    parentDeclSyntax: PluginMessage.Syntax?
  )

  /// Optionally implemented message to load a dynamic link library.
  /// 'moduleName' can be used as a hint indicating that the library
  /// provides the specified module.
  case loadPluginLibrary(
    libraryPath: String,
    moduleName: String
  )
}

internal enum PluginToHostMessage: Codable {
  case getCapabilityResult(
    capability: PluginMessage.PluginCapability
  )

  case expandFreestandingMacroResult(
    expandedSource: String?,
    diagnostics: [PluginMessage.Diagnostic]
  )

  case expandAttachedMacroResult(
    expandedSources: [String]?,
    diagnostics: [PluginMessage.Diagnostic]
  )

  case loadPluginLibraryResult(
    loaded: Bool,
    diagnostics: [PluginMessage.Diagnostic]
  )
}

/*namespace*/ internal enum PluginMessage {
  static var PROTOCOL_VERSION_NUMBER: Int { 4 }  // Added 'loadPluginLibrary'.

  struct PluginCapability: Codable {
    var protocolVersion: Int

    /// Optional features this plugin provides.
    ///  * 'load-plugin-library': 'loadPluginLibrary' message is implemented.
    var features: [String]?
  }

  struct MacroReference: Codable {
    var moduleName: String
    var typeName: String

    // The name of 'macro' declaration the client is using.
    var name: String
  }

  enum MacroRole: String, Codable {
    case expression
    case freeStandingDeclaration
    case accessor
    case memberAttribute
    case member
    case peer
    case conformance
  }

  struct SourceLocation: Codable {
    /// A file ID consisting of the module name and file name (without full path),
    /// as would be generated by the macro expansion `#fileID`.
    var fileID: String

    /// A full path name as would be generated by the macro expansion `#filePath`,
    /// e.g., `/home/taylor/alison.swift`.
    var fileName: String

    /// UTF-8 offset of the location in the file.
    var offset: Int

    var line: Int
    var column: Int
  }

  struct Diagnostic: Codable {
    enum Severity: String, Codable {
      case error
      case warning
      case note
    }
    struct Position: Codable {
      var fileName: String
      /// UTF-8 offset in the file.
      var offset: Int

      static var invalid: Self {
        .init(fileName: "", offset: 0)
      }
    }
    struct PositionRange: Codable {
      var fileName: String
      /// UTF-8 offset of the start of the range in the file.
      var startOffset: Int
      /// UTF-8 offset of the end of the range in the file.
      var endOffset: Int

      static var invalid: Self {
        .init(fileName: "", startOffset: 0, endOffset: 0)
      }
    }
    struct Note: Codable {
      var position: Position
      var message: String
    }
    struct FixIt: Codable {
      struct Change: Codable {
        var range: PositionRange
        var newText: String
      }
      var message: String
      var changes: [Change]
    }
    var message: String
    var severity: Severity
    var position: Position
    var highlights: [PositionRange]
    var notes: [Note]
    var fixIts: [FixIt]
  }

  struct Syntax: Codable {
    enum Kind: String, Codable {
      case declaration
      case statement
      case expression
      case type
      case pattern
      case attribute
    }
    var kind: Kind
    var source: String
    var location: SourceLocation
  }
}
